﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using NPOI.SS.Formula.Functions;

namespace Lg.Core.Extensions
{
    public static class BaseExtensions
    {
        public static int ToInt16(this string i, int d)
        {
            try { d = Convert.ToInt16(i); } catch { }

            return d;

        }
        public static int ToInt32(this string s, int d)
        {
            try { d = Convert.ToInt32(s); } catch { }
            return d;
        }
        public static long ToInt64( this string i, long d)
        {
            try { d = Convert.ToInt64(i); } catch { }
            return d;
        }
        public static double ToDouble(this string i, double d)
        {
            try { d = Convert.ToDouble(i); } catch { }
            return d;
        }
        public static decimal ToDecimal(this string i, decimal d)
        {
            try { d = Convert.ToDecimal(i); } catch { }
            return d;
        }
        public static DateTime ToDateTime(this string i, DateTime d)
        {
            try { d = Convert.ToDateTime(i); } catch { }
            return d;
        }
                
        #region  [DataTable 转换成 T 实体集合]
        /// <summary>
        /// DataTable的第一行转成实体Model
        /// </summary>
        /// <param name="dt">DataTable</param>
        /// <returns>实体</returns>
        public static T? ToModel<T>(this DataTable dt) where T : new()
        {
            if (dt == null || dt.Rows.Count == 0)
            {
                return default(T);
            }
            T model = new T();
            DataRow dr = dt.Rows[0];
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                PropertyInfo propertyInfo = model.GetType().GetProperty(dr.Table.Columns[i].ColumnName)!;
                if (propertyInfo != null && dr[i] != DBNull.Value)
                {
                    try
                    {
                        propertyInfo.SetValue(model, dr[i]);
                    }
                    catch
                    {
                        if (propertyInfo.PropertyType.Name == "String")
                        {
                            propertyInfo.SetValue(model, dr[i].ToString());
                        }
                    }
                }

            }
            return model;
        }
        #endregion

        #region  [DataTable 转换成 List<T> 实体集合]
        /// <summary>
        /// DataTable转成List<T>
        /// </summary>
        /// <param name="dt">DataTable</param>
        /// <returns>实体</returns>
        public static List<T>? ToList<T>(this DataTable dt) where T : new()
        {
            if (dt == null || dt.Rows.Count == 0)
            {
                return null;
            }
            List<T> list = new List<T>();
            foreach(DataRow dr in dt.Rows)
            {
                T model = new T();
                for (int i = 0; i < dt.Columns.Count; i++)
                {
                    PropertyInfo propertyInfo = model.GetType().GetProperty(dr.Table.Columns[i].ColumnName)!;
                    if (propertyInfo != null && dr[i] != DBNull.Value)
                    {
                        try
                        {
                            propertyInfo.SetValue(model, dr[i]);
                        }
                        catch
                        {
                            if (propertyInfo.PropertyType.Name == "String")
                            {
                                propertyInfo.SetValue(model, dr[i].ToString());
                            }
                        }
                    }

                }
                list.Add(model);
            }            
            return list;
        }
        #endregion

        public static DataTable? Format(this DataTable table,Func<string,string?,string?> format)
        {
            DataTable dt = new DataTable();
            foreach (DataColumn colmn in table.Columns)
            {
                dt.Columns.Add(colmn.ColumnName);
            }
            if (table!= null && table.Rows.Count > 0)
            {
                foreach(DataRow dr in table.Rows)
                {
                    DataRow _dr = dt.NewRow();
                    foreach(DataColumn colmn in table.Columns)
                    {
                        string? val=format(colmn.ColumnName, Convert.ToString(dr[colmn.ColumnName]));
                        if(val != null)
                        {
                            _dr[colmn.ColumnName] = val;
                        }
                        else
                        {
                            _dr[colmn.ColumnName] = Convert.ToString(dr[colmn.ColumnName]);
                        }
                    }
                    dt.Rows.Add(_dr);
                }
            }
            return dt;
        }

        #region [model and List<model>]
        /// <summary>
        /// 将实体序列化为json字符串
        /// </summary>
        /// <typeparam name="T">用于约束的范型，可实例化</typeparam>
        /// <param name="model">实参</param>
        /// <returns></returns>
        public static string ToJsonString<T>(this T model, string format = "yyyy-MM-dd") where T : new()
        {
            
            IsoDateTimeConverter iso = new IsoDateTimeConverter() { DateTimeFormat = format };
            try
            {
                return JsonConvert.SerializeObject(model, iso);
            }
            catch
            {
                throw new Exception("实参类型无法序列化！");
            }
        }
        /// <summary>
        /// 将List<model>对像序列化为json字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static string ToJsonString<T>(this List<T> list, string format = "yyyy-MM-dd") where T : new()
        {
            IsoDateTimeConverter iso = new IsoDateTimeConverter() { DateTimeFormat = format };
            try
            {
                return JsonConvert.SerializeObject(list, iso);
            }
            catch
            {
                throw new Exception("实参类型无法序列化！");
            }
        }


        /// <summary>
        /// 复制实体数据
        /// </summary>
        /// <typeparam name="T">需要复制数据的实体类型</typeparam>
        /// <typeparam name="U">被复制的实体类型</typeparam>
        /// <param name="t">需要复制数据的实体对像</param>
        /// <param name="u">被复制的实体对像</param>
        /// <returns>T对像</returns>
        public static T CopyData<T, U>(this T t, U u) where T : notnull
        {
            PropertyInfo[] Propertys = t.GetType().GetProperties();
            Propertys.AsParallel().ForAll(pi =>
            {
             
                PropertyInfo propertyInfo = u!.GetType().GetProperty(pi.Name)!;
                if (propertyInfo != null)
                {
                    object value = propertyInfo.GetValue(u, null)!;
                    if (value != null)
                    {
                        pi.SetValue(t, value, null);
                    }
                }

            });
            return t;
        }  

        public static T CopyData<T, U>(this T t, U u, CopyTypeOptions options, params string[] param)
        {
            PropertyInfo[] Propertys = t!.GetType().GetProperties();
            Propertys.AsParallel().ForAll(pi =>
            {
                if(options==CopyTypeOptions.include&&!param.Contains(pi.Name))
                {
                    return;
                }else if (options == CopyTypeOptions.exclude && param.Contains(pi.Name))
                {
                    return;
                }
                PropertyInfo propertyInfo = u!.GetType().GetProperty(pi.Name, pi.PropertyType)!;
                if (propertyInfo != null)
                {
                    object value = propertyInfo.GetValue(u, null)!;
                    if (value != null)
                    {
                        pi.SetValue(t, value, null);
                    }
                }

            });
            return t;
        }
        public enum CopyTypeOptions
        {
            include,
            exclude
        }
        /// <summary>
        /// 判断两个相同类型的实体，并记录相同属性值的变化(用于记录实体编辑日志)
        /// </summary>
        /// <typeparam name="T">范型类弄</typeparam>
        /// <param name="model">当前实体，改变后的新实体</param>
        /// <param name="oldModel">修改之前的数据实体</param>
        /// <param name="param">指定要比对的属性名数组</param>
        /// <returns>字符串</returns>
        public static string GetDiffLog<T>(this T model, T oldModel, params string[] param) where T : new()
        {
            string log = "";
            PropertyInfo[] Propertys = model!.GetType().GetProperties();
            Propertys.AsParallel().ForAll(pi =>
            {
                if (param.Contains(pi.Name))
                {
                    string oval = Convert.ToString(oldModel!.GetType().GetProperty(pi.Name, pi.PropertyType)!.GetValue(oldModel, null))!;
                    string val = Convert.ToString(model.GetType().GetProperty(pi.Name, pi.PropertyType)!.GetValue(model, null))!;
                    if (val != oval)
                    {
                        log += $"{pi.Name}: [{oval} => {val}];";
                    }
                }
            });
            return log;
        }
        public static string GetDiffLog<T>(this T model, T oldModel, object? obj, params string[] param) where T : new()
        {
            string log = "";
            PropertyInfo[] Propertys = model!.GetType().GetProperties();
            Propertys.AsParallel().ForAll(pi =>
            {
                if (!param.Contains(pi.Name))
                {
                    string oval = Convert.ToString(oldModel!.GetType().GetProperty(pi.Name, pi.PropertyType)!.GetValue(oldModel, null))!;
                    string val = Convert.ToString(model.GetType().GetProperty(pi.Name, pi.PropertyType)!.GetValue(model, null))!;
                    if (val != oval)
                    {
                        log += $"{pi.Name}: [{oval} => {val}];";
                    }

                }
            });
            return log;
        }
        public static string GetDiffLog<T>(this T model, T oldModel) where T : new()
        {
            string log = "";
            PropertyInfo[] Propertys = model!.GetType().GetProperties();
            Propertys.AsParallel().ForAll(pi =>
            {

                string oval = Convert.ToString(oldModel!.GetType().GetProperty(pi.Name, pi.PropertyType)!.GetValue(oldModel, null))!;
                string val = Convert.ToString(model.GetType().GetProperty(pi.Name, pi.PropertyType)!.GetValue(model, null))!;
                if (val != oval)
                {
                    log += $"{pi.Name}: [{oval} => {val}];";
                }
            });
            return log;
        }
        #endregion

        
    }
}
